<?php
/*
 * @Description    : 微信支付异步通知接口
 * @Version        : 1.0.0
 * @Author         : QianLong
 * @Date           : 2021-04-05 17:13:54
 * @LastEditors    : QianLong
 * @LastEditTime   : 2022-05-28 17:25:59
 */

namespace app\notify\controller;

use app\common\RedisCache;
use think\facade\Request;
use Yurun\Util\HttpRequest;
use app\common\service\wxpay\Config;
use app\common\service\wxpay\CertificateVerifier;
use think\facade\Db;
use app\lib\exception\ApiException;
use Ecmpay\Ecmpay\Ecmpay;

class Wxpay extends \app\BaseController
{
    protected $redisCache;
    protected $platformSetting;
    protected $infoData;
    public function initialize()
    {
        $this->redisCache = new RedisCache();
        $this->platformSetting = $this->redisCache::getSysPaymentSetting();
        if (!isset($this->platformSetting['pay_platform']) || $this->platformSetting['pay_platform'] != 'ecmpay') {
            $this->infoData = (new Config)->getSetting();
        } else {
            $ecmpaySetting = $this->redisCache::getSysPaySetting('wxpay');
            Ecmpay::init(['app_id' => $ecmpaySetting['app_id'], 'auth_app_id' => $ecmpaySetting['auth_app_id'], 'appSecret' => $ecmpaySetting['app_secret']]);
        }
    }
    public function url()
    {
        if (!isset($this->platformSetting['pay_platform']) || $this->platformSetting['pay_platform'] != 'ecmpay') {
            return $this->wxurl();
        } else {
            $postData = input('param.');
            if (!empty($postData)) {
                if (!Ecmpay::signVerify($postData)) {
                    throw new ApiException('喵付通支付签名校验失败');
                }
                if ($postData['event'] == 'PAYMENT_SUCCESS') {
                    //具体参数详细请看文档：http://doc.21ds.cn/index?project_id=4683630058798691&doc_id=4687155804231000
                }
                echo 'success';
            } else {
                echo "empty";
            }
        }
    }
    public function wxurl()
    {
        $header = Request::header();
        $time = time();
        $WxPaySerial = (isset($header['Wechatpay-Serial'])) ? $header['Wechatpay-Serial'] : ((isset($header['wechatpay-serial'])) ? $header['wechatpay-serial'] : '');
        $WxTimestamp = (isset($header['Wechatpay-Timestamp'])) ? $header['Wechatpay-Timestamp'] : ((isset($header['wechatpay-timestamp'])) ? $header['wechatpay-timestamp'] : '');
        $WxNonce = (isset($header['Wechatpay-Nonce'])) ? $header['Wechatpay-Nonce'] : ((isset($header['wechatpay-nonce'])) ? $header['wechatpay-nonce'] : '');
        $WxSignature = (isset($header['Wechatpay-Signature'])) ? $header['Wechatpay-Signature'] : ((isset($header['wechatpay-signature'])) ? $header['wechatpay-signature'] : '');
        if (!isset($WxPaySerial, $WxSignature, $WxTimestamp, $WxNonce)) {
            return false;
        }
        $body = file_get_contents('php://input');
        $message = "$WxTimestamp\n$WxNonce\n$body\n";
        $wechatCert = Db::name('WechatCertificates')->field('serial_no,certificate')->where('expire_time', '>', $time)->order('effective_time', 'desc')->select();
        if (empty($wechatCert)) {
            $wechatCert = $this->getWxCert();
        }
        $certSerialNo = [];
        $certificate = [];
        foreach ($wechatCert as $key => $vo) {
            array_push($certSerialNo, $vo['serial_no']);
            array_push($certificate, $vo['certificate']);
        }
        if (!in_array($WxPaySerial, $certSerialNo)) {
            throw new ApiException("证书序列号不匹配，请检查");
        }
        $verify = (new CertificateVerifier($certificate))->verify($WxPaySerial, $message, $WxSignature);
        if (!$verify) {
            throw new ApiException("证书校验失败");
        }
        $postData = json_decode($body, true);
        if ($postData['resource']) {
            $configObj = new Config;
            $data = $configObj->decryptToString($postData['resource']['associated_data'], $postData['resource']['nonce'], $postData['resource']['ciphertext']);
            $data = json_decode($data, true);
            if ($data) {
                if ($data['trade_state'] == 'SUCCESS') {
                    //支付成功，完成你的逻辑
                    //例如连接数据库，获取付款金额$result['amount']['total']，获取订单号$result['out_trade_no']修改数据库中的订单状态等;
                    //订单总金额，单位为分：$result['amount']['total']
                    //用户支付金额，单位为分：$result['amount']['payer_total']
                    //商户订单号：$result['out_trade_no']
                    //微信支付订单号：$result['transaction_id']
                    //银行类型：$result['bank_type']
                    //支付完成时间：$result['success_time'] 格式为YYYY-MM-DDTHH:mm:ss+TIMEZONE
                    //用户标识：$result['payer']['openid']
                    //交易状态：$result['trade_state']
                    //具体详细请看微信文档：https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pay/transactions/chapter3_11.shtml
                    echo 'success';
                }
            }
        }
    }
    public function test()
    {
        $this->getWxCert();
    }
    /**
     * 微信支付公钥证书文件
     * @return void
     * @author QianLong <87498106@qq.com>
     * @date 2021-04-06 16:07:14
     * @editAuthor QianLong <87498106@qq.com>
     * @editDescription 
     * @editDate 2021-04-06 16:07:14
     */
    private function getWxCert()
    {
        $configObj = new Config;
        $url = 'https://api.mch.weixin.qq.com/v3/certificates';
        $token = $configObj->getAuthorization($url, null, 'GET');
        $http = new HttpRequest;
        $response = $http->header('Authorization', $token)->header('Accept', 'application/json')->get($url);
        $result = json_decode($response->body(), true);
        $insertAll = [];
        $hasCert = Db::name('WechatCertificates')->select()->toArray();
        $certNo = [];
        foreach ($hasCert as $key => $vo) {
            array_push($certNo, $vo['serial_no']);
        }
        if (isset($result['data']) && !empty($result['data'])) {
            foreach ($result['data'] as $key => $vo) {
                if (!in_array($vo['serial_no'], $certNo)) {
                    $certData['serial_no'] = $vo['serial_no'];
                    $certData['effective_time'] = strtotime($vo['effective_time']);
                    $certData['expire_time'] = strtotime($vo['expire_time']);
                    $certData['certificate'] = $configObj->decryptToString($vo['encrypt_certificate']['associated_data'], $vo['encrypt_certificate']['nonce'], $vo['encrypt_certificate']['ciphertext']);
                    $insertAll[] = $certData;
                }
            }
        }
        if (!empty($insertAll)) {
            Db::name('WechatCertificates')->insertAll($insertAll);
        }
        return $insertAll;
    }
}
